/**
 * www.easyplatform.cn ©2016
 */
package cn.easyplatform.studio.utils;

import cn.easyplatform.entities.BaseEntity;
import cn.easyplatform.entities.ContentEntity;
import cn.easyplatform.entities.EntityInfo;
import cn.easyplatform.entities.beans.list.ListBean;
import cn.easyplatform.entities.beans.page.PageBean;
import cn.easyplatform.entities.beans.report.JasperReportBean;
import cn.easyplatform.entities.beans.table.TableBean;
import cn.easyplatform.entities.beans.table.TableField;
import cn.easyplatform.entities.transform.TransformerFactory;
import cn.easyplatform.lang.Lang;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.lang.stream.StringOutputStream;
import cn.easyplatform.studio.StudioApp;
import cn.easyplatform.studio.cmd.biz.UpdateCmd;
import cn.easyplatform.studio.cmd.entity.CheckCmd;
import cn.easyplatform.studio.cmd.entity.CopyCmd;
import cn.easyplatform.studio.cmd.entity.SaveCmd;
import cn.easyplatform.studio.cmd.link.CheckLinkCmd;
import cn.easyplatform.studio.cmd.version.ExportCmd;
import cn.easyplatform.studio.cmd.version.GetEntryCmd;
import cn.easyplatform.studio.context.Contexts;
import cn.easyplatform.studio.vos.*;
import cn.easyplatform.studio.web.editors.Editor;
import cn.easyplatform.studio.web.editors.SimpleEditorFactory;
import cn.easyplatform.studio.web.layout.WorkbenchController;
import cn.easyplatform.type.EntityType;
import cn.easyplatform.type.FieldType;
import cn.easyplatform.type.SubType;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.xmlbeans.impl.xb.xsdschema.Public;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.*;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @author <a href="mailto:shiny_vc@163.com">陈云亮</a> <br/>
 * @since 2.0.0 <br/>
 */
public final class StudioUtil {
    private static final String salt = "&%2155***&&%%$$#@";
    /**
     * 查找类中的方法
     *
     * @param clazz
     * @param name
     * @param paramTypes
     * @return
     */
    public static Method findMethod(Class<?> clazz, String name,
                                    Class<?>... paramTypes) {
        Class<?> searchType = clazz;
        while (searchType != null) {
            Method[] methods = (searchType.isInterface() ? searchType
                    .getMethods() : searchType.getDeclaredMethods());
            for (Method method : methods) {
                if (name.equals(method.getName())
                        && (paramTypes == null || Arrays.equals(paramTypes,
                        method.getParameterTypes()))) {
                    return method;
                }
            }
            searchType = searchType.getSuperclass();
        }
        return null;
    }

    /**
     * 保存参数
     *
     * @param entity
     * @param code
     */
    public static <T extends BaseEntity> void save(T entity, char code) {
        EntityInfo ei = new EntityInfo();
        if (entity instanceof ContentEntity) {
            ei.setContent(((ContentEntity) entity).getContent());
        } else {
            StringBuilder sb = new StringBuilder();
            StringOutputStream os = new StringOutputStream(sb);
            TransformerFactory.newInstance().transformToXml(entity, os);
            ei.setContent(sb.toString());
        }
        if (entity instanceof PageBean) {
            PageBean pageBean = (PageBean) entity;
            PageBean pageBean1 = pageBean.clone();
            ei.setExt0(pageBean1.getAjax());
            ei.setExt1(pageBean1.getMil());
            pageBean1.setAjax(null);
            pageBean1.setMil(null);
            StringBuilder sb = new StringBuilder();
            StringOutputStream os = new StringOutputStream(sb);
            TransformerFactory.newInstance().transformToXml(pageBean1, os);
            ei.setContent(sb.toString());
        }
        ei.setId(entity.getId());
        ei.setName(entity.getName());
        ei.setDescription(entity.getDescription());
        ei.setType(entity.getType());
        ei.setSubType(entity.getSubType());
        ei.setStatus(code);
        StudioApp.execute(new SaveCmd(ei));
    }

    /**
     * 把xml转成报表参数
     *
     * @param xml
     * @return
     */
    public final static String convertReportContent(String xml) {
        JasperReportBean rb = TransformerFactory.newInstance()
                .transformFromXml(JasperReportBean.class, Lang.ins(xml));
        try {
            String c = new String(rb.getContent(), "utf8");
            StringBuilder sb = new StringBuilder("<report>\n");
            if (!Strings.isBlank(rb.getDsId()))
                sb.append("<dsId>").append(rb.getDsId()).append("</dsId>\n");
            if (!Strings.isBlank(rb.getQuery()))
                sb.append("<query>").append(rb.getQuery()).append("</query>\n");
            if (!Strings.isBlank(rb.getGroupBy()))
                sb.append("<groupBy>").append(rb.getGroupBy())
                        .append("</groupBy>\n");
            if (!Strings.isBlank(rb.getOrderBy()))
                sb.append("<orderBy>").append(rb.getOrderBy())
                        .append("</orderBy>\n");
            sb.append("<content>").append(c).append("</content>\n");
            if (rb.getOnRecord() != null) {
                if (Strings.isBlank(rb.getOnRecord().getId()))
                    sb.append("<onRecord>")
                            .append(rb.getOnRecord().getContent())
                            .append("</onRecord>\n");
                else if (!Strings.isBlank(rb.getOnRecord().getId()))
                    sb.append("<onRecord id=\"")
                            .append(rb.getOnRecord().getId()).append("\"/>\n");
            }
            if (rb.getOnGroup() != null) {
                if (Strings.isBlank(rb.getOnGroup().getId()))
                    sb.append("<onGroup>").append(rb.getOnGroup().getContent())
                            .append("</onGroup>\n");
                else if (!Strings.isBlank(rb.getOnGroup().getId()))
                    sb.append("<onGroup id=\"").append(rb.getOnGroup().getId())
                            .append("\"/>\n");
            }
            sb.append("</report>");
            return sb.toString();
        } catch (UnsupportedEncodingException e) {
        }
        rb = null;
        return xml;
    }

    /**
     * 从json转对象
     *
     * @param content
     * @return
     */
    public final static Map fromJson(String content) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.readValue(content, Map.class);
        } catch (Exception e) {
            throw Lang.wrapThrow(e);
        }
    }

    /**
     * 把对象转成json
     *
     * @param obj
     * @return
     */
    public final static String toJson(Object obj) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.writeValueAsString(obj);
        } catch (Exception e) {
            throw Lang.wrapThrow(e);
        }
    }

    /**
     * 判断是否有新增的权限
     *
     * @param ev
     * @return
     */
    public final static boolean isAddPermission(EntityVo ev) {
        LoginUserVo loginUserVo = Contexts.getUser();
        boolean isAuthorized = false;
        if (ev.getType().equals(EntityType.RESOURCE.getName())) {
            if (ev.getSubType().equals(SubType.JOB.getName()))
                isAuthorized = loginUserVo.isAuthorized("jobAdd");
            else
                isAuthorized = loginUserVo.isAuthorized(ev.getType().toLowerCase() + "Add");
        } else
            isAuthorized = loginUserVo.isAuthorized(ev.getType().toLowerCase() + "Add");
        return isAuthorized;
    }

    /**
     * 判断是否有删除的权限
     *
     * @param ev
     * @return
     */
    public final static boolean isDeletePermission(EntityVo ev) {
        LoginUserVo loginUserVo = Contexts.getUser();
        boolean isAuthorized = false;
        if (ev.getType().equals(EntityType.RESOURCE.getName())) {
            if (ev.getSubType().equals(SubType.JOB.getName()))
                isAuthorized = loginUserVo.isAuthorized("jobDelete");
            else
                isAuthorized = loginUserVo.isAuthorized(ev.getType().toLowerCase() + "Delete");
        } else
            isAuthorized = loginUserVo.isAuthorized(ev.getType().toLowerCase() + "Delete");
        return isAuthorized;
    }

    /**
     * 判断是否有修改的权限
     *
     * @param ev
     * @return
     */
    public final static boolean isEditPermission(EntityVo ev) {
        LoginUserVo loginUserVo = Contexts.getUser();
        boolean isAuthorized = false;
        if (ev.getType().equals(EntityType.RESOURCE.getName())) {
            if (ev.getSubType().equals(SubType.JOB.getName()))
                isAuthorized = loginUserVo.isAuthorized("jobEdit");
            else
                isAuthorized = loginUserVo.isAuthorized(ev.getType().toLowerCase() + "Edit");
        } else
            isAuthorized = loginUserVo.isAuthorized(ev.getType().toLowerCase() + "Edit");
        return isAuthorized;
    }

    /**
     * 显示拷贝参数页面
     *
     * @param workbench
     * @param page
     * @param entityId
     */
    public final static void showInputDialog(final WorkbenchController workbench, final Page page, final String entityId, final boolean copy) {
        Vlayout hl = new Vlayout();
        hl.setSpacing("10px");
        hl.setSclass("form-group");
        hl.setHflex("1");
        Label label = new Label((copy ? Labels.getLabel("navi.paste") : Labels.getLabel("editor.export.comment")) + ":");
        label.setParent(hl);
        label.setZclass("h4");
        Textbox tb = new Textbox(entityId);
        tb.setZclass("form-control");
        tb.setParent(hl);
        tb.setConstraint("no empty");
        Window win = new Window(copy ? Labels.getLabel("button.copy") : Labels.getLabel("button.export"), "normal", true);
        win.setPage(page);
        win.setHeight("180px");
        win.setWidth("350px");
        hl.setParent(win);
        A btn = new A(Labels.getLabel("button.ok"));
        btn.setStyle("position:absolute;width:100px");
        btn.setTop("120px");
        btn.setLeft("120px");
        btn.setZclass("btn btn-primary");
        btn.setParent(win);
        btn.addEventListener(Events.ON_CLICK, new EventListener<Event>() {
            @Override
            public void onEvent(Event event) throws Exception {
                Textbox tb = (Textbox) event.getTarget().getRoot().query("textbox");
                String id = tb.getValue().trim();
                if (copy) {
                    if (StudioApp.execute(new CheckCmd(id))) {
                        WebUtils.showError(Labels.getLabel("entity.exists.id",
                                new String[]{tb.getValue()}));
                        return;
                    }
                    BaseEntity entity = StudioApp.execute(event.getTarget(),
                            new CopyCmd(entityId, id));
                    if (entity != null) {
                        if(entity instanceof TableBean){
                            TableBean tableBean = (TableBean) entity;
                            List<FieldVo> params = new ArrayList<FieldVo>();
                            String insertSql = "INSERT INTO sys_table_field_info(table1id,table1name,table1description,field1name,field1type,field1length,field1decimal,field1description,field1notnull,field1orderNo,field1acc,field1defaultvalue) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)";
                            int i = 1;
                            for (TableField tf : tableBean.getFields()) {
                                params.clear();
                                params.add(new FieldVo(FieldType.VARCHAR, tableBean.getId()));//表名
                                params.add(new FieldVo(FieldType.VARCHAR, tableBean.getName()));//表中文名
                                params.add(new FieldVo(FieldType.VARCHAR, tableBean.getDescription()));//表描述
                                params.add(new FieldVo(FieldType.VARCHAR, tf.getName()));//字段名
                                params.add(new FieldVo(FieldType.VARCHAR, tf.getType()));//字段类型
                                params.add(new FieldVo(FieldType.VARCHAR, tf.getLength()));//字段长度
                                params.add(new FieldVo(FieldType.VARCHAR, tf.getDecimal()));//小数位
                                params.add(new FieldVo(FieldType.VARCHAR, tf.getDescription()));//字段说明
                                params.add(new FieldVo(FieldType.VARCHAR, tf.isNotNull()));//是否可为空
                                params.add(new FieldVo(FieldType.VARCHAR, i + ""));//字段顺序
                                params.add(new FieldVo(FieldType.VARCHAR, tf.getAcc()));//关联字段
                                params.add(new FieldVo(FieldType.VARCHAR, tf.getDefaultValue()));//字段默认值
                                StudioApp.execute(new UpdateCmd(tableBean.getSubType(), insertSql, params));
                                i++;
                            }
                        }
                        workbench.createEditor(entity, 'U');
                        workbench.getEntityBar().refreshEntity();
                        workbench.getEntityWindowBar().refreshEntity();
                    } else
                        WebUtils.showError(Labels.getLabel("entity.no.exists",
                                new String[]{entityId}));
                } else {
                    EntityInfo entityInfo = StudioApp.execute(event.getTarget(), new GetEntryCmd(entityId));
                    if (entityInfo != null) {
                        List<EntityInfo> entites = new ArrayList<EntityInfo>(1);
                        entites.add(entityInfo);
                        StudioUtil.export(event.getTarget(), entites, id, entityInfo.getVersion(), entityInfo.getVersion());
                    }
                }
                event.getTarget().getRoot().detach();
            }
        });
        tb.addForward(Events.ON_OK, btn, Events.ON_CLICK);
        win.doHighlighted();
    }

    /**
     * 显示指定参数的版本记录
     *
     * @param workbench
     * @param vo
     */
    public final static void showHistory(WorkbenchController workbench, EntityVo vo) {
        Editor editor = workbench.checkEditor(Editor.HISTORY_EDITOR_ID);
        if (editor == null)
            SimpleEditorFactory.createEditor(workbench,
                    Editor.HISTORY_EDITOR_ID).create(vo);
        else
            editor.create(vo);
    }

    /**
     * 导出参数
     *
     * @param target
     * @param entites
     * @param comment
     * @param min
     * @param max
     */
    public final static void export(Component target, List<EntityInfo> entites, String comment, int min, int max) {
        IXVo vo = new IXVo();
        String pid = Contexts.getProject().getId();
        vo.setId(pid + "_" + min + "-" + max);
        vo.setFirstNo(min);
        vo.setLastNo(max);
        vo.setDesp(comment);
        vo.setEntities(entites);
        vo.setUser(Contexts.getUser().getUserId());
        vo.setProjectId(pid);
        vo.setDate(new Date());
        if (StudioApp.execute(target, new ExportCmd(vo))) {
            ZipUtil.createZip(vo, pid + ".dat", vo.getId() + ".zip");
        } else
            WebUtils.showError(Labels.getLabel("editor.export.title"));
    }

    /**
     * 导出字典
     *
     * @param dicVos
     * @param comment
     */
    public final static void exportDic(List<DicVo> dicVos, String comment) {
        IXVo vo = new IXVo();
        String pid = Contexts.getProject().getId();
        vo.setDesp(comment);
        vo.setDicVos(dicVos);
        vo.setUser(Contexts.getUser().getUserId());
        vo.setProjectId(pid);
        vo.setDate(new Date());
        ZipUtil.createZip(vo, pid + "dic.dat", pid + "dic.zip");
    }

    /**
     * 导出字典
     *
     * @param menuVos
     * @param comment
     */
    public final static void exportMenu(List<MenuInfoVo> menuVos, String comment) {
        IXVo vo = new IXVo();
        String pid = Contexts.getProject().getId();
        vo.setDesp(comment);
        vo.setMenuInfoVos(menuVos);
        vo.setUser(Contexts.getUser().getUserId());
        vo.setProjectId(pid);
        vo.setDate(new Date());
        ZipUtil.createZip(vo, pid + "menu.dat", pid + "menu.zip");
    }

    /**
     * 导出多国语言
     *
     * @param dicVos
     * @param comment
     */
    public final static void exportMessage(List<MessageVo> dicVos, String comment) {
        IXVo vo = new IXVo();
        String pid = Contexts.getProject().getId();
        vo.setDesp(comment);
        vo.setMessageVos(dicVos);
        vo.setUser(Contexts.getUser().getUserId());
        vo.setProjectId(pid);
        vo.setDate(new Date());
        ZipUtil.createZip(vo, pid + "Message.dat", pid + "Message.zip");
    }

    /**
     * 导出文件
     *
     * @param fileVos
     * @param comment
     */
    public final static void exportFile(List<UploadHistVo> fileVos, String comment) {
        IXVo vo = new IXVo();
        String pid = Contexts.getProject().getId();
        vo.setDesp(comment);
        vo.setFileVos(fileVos);
        vo.setUser(Contexts.getUser().getUserId());
        vo.setProjectId(pid);
        vo.setDate(new Date());
        ZipUtil.createZip(vo, pid + "File.dat", pid + "File.zip");
    }

    /**
     * 数据库参数类型生成页面参数类型
     * @param entityType    数据库参数类型
     * @param entitySubType 数据库参数二级类型
     * @return  对应字符串
     */
    public final static String getSringWithEntityType(String entityType, String entitySubType) {
        String typeStr = null;
        if (EntityType.TASK.getName().equals(entityType)) {
            typeStr = Labels.getLabel("entity.task");
        } else if (EntityType.PAGE.getName().equals(entityType)) {
            typeStr = Labels.getLabel("entity.page");
        } else if (EntityType.TABLE.getName().equals(entityType)) {
            typeStr = Labels.getLabel("entity.table");
        } else if (EntityType.DATALIST.getName().equals(entityType)) {
            typeStr = Labels.getLabel("entity.list");
        } else if (EntityType.LOGIC.getName().equals(entityType)) {
            typeStr = Labels.getLabel("entity.logic");
        } else if (EntityType.API.getName().equals(entityType)) {
            typeStr = Labels.getLabel("entity.api");
        } else if (EntityType.BATCH.getName().equals(entityType)) {
            typeStr = Labels.getLabel("entity.batch");
        } else if (EntityType.BPM.getName().equals(entityType)) {
            typeStr = Labels.getLabel("entity.bpm");
        } else if (EntityType.REPORT.getName().equals(entityType)) {
            typeStr = Labels.getLabel("entity.report");
        } else if (EntityType.RESOURCE.getName().equals(entityType)) {
            if (SubType.JOB.getName().equals(entitySubType)) {
                typeStr = Labels.getLabel("entity.job");
            } else {
                typeStr = Labels.getLabel("entity.page.other");
            }
        }
        return typeStr;
    }

    /**
     * 数据库参数类型生成页面参数类型
     * @param entityType    数据库参数类型
     * @param entitySubType 数据库参数二级类型
     * @return  对应字符串
     */
    public final static String getStringWithEntityTypeInTask(String entityType, String entitySubType) {
        String typeStr = null;
        if (EntityType.TASK.getName().equals(entityType)) {
            typeStr = "F";
        } else if (EntityType.PAGE.getName().equals(entityType)) {
            typeStr = "P";
        } else if (EntityType.TABLE.getName().equals(entityType)) {
            typeStr = "T";
        } else if (EntityType.DATALIST.getName().equals(entityType)) {
            typeStr = "Q";
        } else if (EntityType.LOGIC.getName().equals(entityType)) {
            typeStr = "L";
        } else if (EntityType.API.getName().equals(entityType)) {
            typeStr = "A";
        } else if (EntityType.BATCH.getName().equals(entityType)) {
            typeStr = "B";
        } else if (EntityType.BPM.getName().equals(entityType)) {
            typeStr = "M";
        } else if (EntityType.REPORT.getName().equals(entityType)) {
            typeStr = "R";
        } else if (EntityType.RESOURCE.getName().equals(entityType)) {
            if (SubType.JOB.getName().equals(entitySubType))
                typeStr = "J";
            else
                typeStr = "S";
        }
        return typeStr;
    }

    /**
     * 获取检查Link关系结果状态对应错误信息
     * @param resultStatus 结果状态
     * @return 错误信息
     */
    public final static String getLinkErrorWithCode(CheckLinkCmd.CheckResultStatus resultStatus) {
        String errorStr = null;
        if (resultStatus.equals(CheckLinkCmd.CheckResultStatus.CHECK_ERROR_NO_EXIT))
            errorStr = Labels.getLabel("entity.diagram.error.noExist");
        else if (resultStatus.equals(CheckLinkCmd.CheckResultStatus.CHECK_ERROR_PARENT_TASK))
            errorStr = Labels.getLabel("entity.diagram.error.taskAddEntity");
        else if (resultStatus.equals(CheckLinkCmd.CheckResultStatus.CHECK_ERROR_CHANGED))
            errorStr = Labels.getLabel("entity.diagram.error.change");
        else if (resultStatus.equals(CheckLinkCmd.CheckResultStatus.CHECK_ERROR_OTHER))
            errorStr = Labels.getLabel("entity.diagram.error.other");
        else if (resultStatus.equals(CheckLinkCmd.CheckResultStatus.CHECK_ERROR_DOUBLE))
            errorStr = Labels.getLabel("entity.diagram.error.double");
        else if (resultStatus.equals(CheckLinkCmd.CheckResultStatus.CHECK_ERROR_PATH_DOUBLE))
            errorStr = Labels.getLabel("entity.diagram.error.path.double");
        return errorStr;
    }

    public final static String getLinkToken(String userID, String projectID, String roleID) {
        String base = userID + "/" + projectID + "/" + roleID + "/" + salt;
        String md5 = DigestUtils.md5Hex(base.getBytes());
        return md5;
    }
}
